package com.riteny.util;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author Riteny
 * 2021/8/30  11:04
 */
public class StringCompareUtil {

    /**
     * 檢查兩個字符串之間的相似度，降序
     *
     * @param existCarList 待驗證相似字符串列表
     * @param compareStr   原字符串
     * @return
     */
    public static List<StringCompareEntity> compareString(String compareStr, List<String> existCarList) {
        return compareString(compareStr, existCarList, 10);
    }

    /**
     * 檢查兩個字符串之間的相似度，降序
     *
     * @param existCarList 待驗證相似字符串列表
     * @param compareStr   原字符串
     * @param size         保留相似度數據的長度
     * @return
     */
    public static List<StringCompareEntity> compareString(String compareStr, List<String> existCarList, Integer size) {

        List<StringCompareEntity> xs = new ArrayList<>();

        for (String str : existCarList) {

            //step1 檢查車牌的相似度
            float y = compareString(compareStr, str);

            //step2 保存當前相似度數據
            StringCompareEntity compareEntity = new StringCompareEntity();
            compareEntity.setCompareString(str);
            compareEntity.setSimilarity(y);

            xs.add(compareEntity);

            //step3 對結果進行排序
            Collections.sort(xs);

            //step4 儅相似度數據大於10時，刪除第一條最小相似度數據
            if (xs.size() > size) {
                xs.remove(xs.size() - 1);
            }
        }

        return xs;
    }


    /**
     * 檢查兩個字符串之間的相似度，降序
     *
     * @param compareStr        原字符串
     * @param existCarList      待驗證相似字符串列表
     * @param compareTargetFunc 原字符串獲取來源，函數式接口
     * @param resultEntityFunc  自定義返回值，函數式接口
     * @param <T>               入參的汎型類型
     * @param <R>               返回的自定義類型
     * @return 相似度對象
     */
    public static <T, R extends StringCompareEntity> List<R> compareString(String compareStr, List<T> existCarList
            , StringCompareFunc<T> compareTargetFunc, ResultEntityFunc<T, R> resultEntityFunc) {
        return compareString(compareStr, existCarList, compareTargetFunc, resultEntityFunc, 10);
    }

    /**
     * @param compareStr        原字符串
     * @param existCarList      待驗證相似字符串列表
     * @param compareTargetFunc 原字符串獲取來源，函數式接口
     * @param resultEntityFunc  自定義返回值，函數式接口
     * @param size              保留相似度數據的長度
     * @param <T>               入參的汎型類型
     * @param <R>               返回的自定義類型
     * @return
     */
    public static <T, R extends StringCompareEntity> List<R> compareString(String compareStr, List<T> existCarList
            , StringCompareFunc<T> compareTargetFunc, ResultEntityFunc<T, R> resultEntityFunc, Integer size) {

        List<R> xs = new ArrayList<>();

        for (T compareEntity : existCarList) {

            String str = compareTargetFunc.getCompareTargetStr(compareEntity);
            //step1 檢查車牌的相似度
            float y = compareString(compareStr, str);

            //step2 保存當前相似度數據
            R result = resultEntityFunc.getResult(compareEntity);
            result.setCompareString(str);
            result.setSimilarity(y);

            xs.add(result);

            //step3 對結果進行排序
            Collections.sort(xs);

            //step4 儅相似度數據大於10時，刪除第一條最小相似度數據
            if (xs.size() > size) {
                xs.remove(xs.size() - 1);
            }
        }

        return xs;
    }


    /**
     * 檢查兩個字符串之間的相似度，降序
     *
     * @param str1 原字符串
     * @param str2 待驗證相似字符串
     * @return 相似度
     */
    public static float compareString(String str1, String str2) {
        int len1 = str1.length();
        int len2 = str2.length();
        int[][] dif = new int[len1 + 1][len2 + 1];
        for (int a = 0; a <= len1; a++) {
            dif[a][0] = a;
        }
        for (int a = 0; a <= len2; a++) {
            dif[0][a] = a;
        }
        int temp;
        for (int i = 1; i <= len1; i++) {
            for (int j = 1; j <= len2; j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    temp = 0;
                } else {
                    temp = 1;
                }
                dif[i][j] = min(dif[i - 1][j - 1] + temp, dif[i][j - 1] + 1,
                        dif[i - 1][j] + 1);
            }
        }

        float similarity = 1 - (float) dif[len1][len2] / Math.max(str1.length(), str2.length());

        return similarity;
    }

    private static int min(int... is) {
        int min = Integer.MAX_VALUE;
        for (int i : is) {
            if (min > i) {
                min = i;
            }
        }
        return min;
    }
}
